/**
 * 说明:
 *   1. 并行任务分解 (ParallelTaskDecomposition)
 *   2. 异步后台作业 (AsyncBackgroundJob)
 *   3. 实时监控 / 轮询服务 (RealTimeMonitoring)
 *
 * 运行方式:
 *   假设已正确安装 GoogleTest，可使用 CMake 或命令行将本文件与 gtest 链接编译:
 *     g++ -std=c++20 -pthread thread_examples_test.cpp -lgtest -lgtest_main -o thread_examples_test
 *     ./thread_examples_test
 */

#include <gtest/gtest.h>

#include <atomic>
#include <condition_variable>
#include <future>
#include <mutex>
#include <numeric>
#include <thread>
#include <vector>
#include <string>

// 便于使用毫秒后缀 (例如 50ms)
using namespace std::chrono_literals;

/**
 * 场景 1：并行任务分解
 *
 * 展示如何把一个大数组分块后交给多个线程并行处理；
 * 测试验证几个位置的结果正确性。
 */
TEST(ThreadExamples, ParallelTaskDecomposition) {
    // 创建一个连续整型数组，内容为 [0, 1, 2, ..., 9999]
    std::vector<int> data(10'000);
    std::iota(data.begin(), data.end(), 0);

    // 根据硬件并发能力决定线程数量，未知时回退到固定值
    std::size_t threadCount = std::thread::hardware_concurrency();
    if (threadCount == 0) {
        threadCount = 4;
    }

    // 计算每个线程要处理的区间大小
    const std::size_t blockSize = data.size() / threadCount;
    std::vector<std::thread> workers;
    workers.reserve(threadCount);

    // 启动多个线程，并行地对各自负责的数据段进行平方
    for (std::size_t i = 0; i < threadCount; ++i) {
        const std::size_t begin = i * blockSize;
        const std::size_t end   = (i == threadCount - 1) ? data.size() : begin + blockSize;

        workers.emplace_back([begin, end, &data] {
            for (std::size_t idx = begin; idx < end; ++idx) {
                data[idx] *= data[idx];
            }
        });
    }

    // 确保所有线程都正常结束
    for (auto& t : workers) {
        t.join();
    }

    // 验证几个位置的值是否已经正确平方
    EXPECT_EQ(data.front(), 0);
    EXPECT_EQ(data[1], 1);
    EXPECT_EQ(data[123], 123 * 123);
    EXPECT_EQ(data.back(), 9'999 * 9'999);
}

/**
 * 场景 2：异步后台作业
 *
 * 主线程模拟执行前台逻辑；后台线程负责周期性记录“心跳”并在结束时写入收尾信息。
 * 使用条件变量等待至少两个心跳事件，以证明线程同步与协作。
 */
TEST(ThreadExamples, AsyncBackgroundJob) {
    std::atomic<bool> done{false};        // 控制后台线程退出的标志
    std::mutex logMutex;                  // 保护日志容器
    std::condition_variable logCv;        // 通知主线程有新日志的条件变量
    std::vector<std::string> logEntries;  // 线程安全地收集日志消息

    std::thread logger([&] {
        // 后台线程周期性写入“Heartbeat”，直到收到 done 信号
        while (!done.load(std::memory_order_acquire)) {
            {
                std::lock_guard<std::mutex> guard(logMutex);
                logEntries.emplace_back("Heartbeat");
            }
            logCv.notify_one();
            std::this_thread::sleep_for(50ms);
        }

        // 退出前添加收尾信息
        {
            std::lock_guard<std::mutex> guard(logMutex);
            logEntries.emplace_back("Logger shutting down");
        }
        logCv.notify_one();
    });

    // 主线程等待至少接收到两个心跳
    {
        std::unique_lock<std::mutex> lock(logMutex);
        ASSERT_TRUE(logCv.wait_for(lock, 500ms, [&] {
            return logEntries.size() >= 2;
        }));
    }

    // 通知后台线程可以退出，并等待其结束
    done.store(true, std::memory_order_release);
    logger.join();

    // 再次检查日志，确保包含“心跳”和“收尾”消息
    {
        std::lock_guard<std::mutex> guard(logMutex);
        ASSERT_FALSE(logEntries.empty());
        EXPECT_GE(logEntries.size(), 3u); // 至少两个心跳 + 一个收尾
        EXPECT_EQ(logEntries.back(), "Logger shutting down");
    }
}

/**
 * 场景 3：实时监控 / 轮询服务
 *
 * 监控线程定期轮询传感器（此处用计数模拟），达到指定次数后触发事件。
 * 使用 std::promise / std::future 向主线程报告，验证协作式停止流程。
 */
TEST(ThreadExamples, RealTimeMonitoring) {
    std::atomic<bool> stopFlag{false};    // 控制监控线程退出的标志
    std::atomic<int> pollCount{0};        // 记录轮询次数，便于测试验证
    std::promise<void> anomalyPromise;    // 用于通知主线程“检测到异常”
    std::future<void> anomalyFuture = anomalyPromise.get_future();
    std::atomic<bool> eventSignaled{false};

    std::thread monitor([&] {
        while (!stopFlag.load(std::memory_order_acquire)) {
            // 模拟轮询：每次循环递增计数
            const int current = pollCount.fetch_add(1) + 1;

            // 到达第 3 次轮询时发出“异常信号”（仅一次）
            if (current == 3 && !eventSignaled.exchange(true)) {
                anomalyPromise.set_value();
            }

            std::this_thread::sleep_for(10ms);
        }
    });

    // 主线程等待异常事件到来（最多等待 200ms）
    EXPECT_EQ(anomalyFuture.wait_for(200ms), std::future_status::ready)
        << "监控线程应在约 30ms 内检测到异常";

    // 发出停止信号并等待线程结束
    stopFlag.store(true, std::memory_order_release);
    monitor.join();

    // 确认轮询次数至少达到 3（确实执行了模拟检测）
    EXPECT_GE(pollCount.load(), 3);
}